//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.


File:

	startui.cpp


Desc:

This file implements the default startup user interface component for 
Windows CE devices.


*/

#include <windows.h>
#include <startui.h>
#include <owner.h>
#include <suirsrc.h>
#ifdef USE_LASS_AUTH
#include <lass.h>
#include <lass_ae.h>
#endif 



// Used to have CanDestroyDialog return true
// if we've already authenticated.
// Always reset to false  in Startup_WantStartupScreen.

const LPWSTR szRegKeyAESystemStartup = TEXT("Comm\\Security\\LASSD\\AE\\{1B38A686-7CDC-4017-A5E9-4C6A9DD7E5BA}");
const LPWSTR szRegValueAEFrequency = TEXT("AEFrequencyValue");

static bool v_isAuthOccured               = false;
static bool fSystemStartupPasswordEnabled = false;
static int  iNumberOfRuns                 = 0;

static OWNER_PROFILE	*g_pOwnerProfile;
static OWNER_NOTES		*g_pOwnerNotes;

static HWND		 g_hwndStartupDialog;
static HINSTANCE g_hinst;

static TCHAR *g_szStartupWork;
static TCHAR *g_szStartupHome;
static TCHAR *g_szStartupTimeFontName;
static TCHAR *g_szStartupPasswordError;
static TCHAR *g_szStartupPasswordErrorTitle;


static WNDPROC oldEditCtlProc;

static bool isAuthRequired()
{

	bool isAuthRequired;
#ifdef USE_LASS_AUTH
	// Auth is not required if a Call To VerifyUser with NO_UI passes.
	isAuthRequired = (FALSE == VerifyUser(&AE_STARTUI,L"StartUI",0,VU_NO_UI,0));
#else

	if ( iNumberOfRuns < 2 )
	{
		isAuthRequired = fSystemStartupPasswordEnabled;
	} else {
		// Only interested in active and screen saver flags
		isAuthRequired = ((GetPasswordStatus() & (PASSWORD_STATUS_SCREENSAVERPROTECT)) != 0);

		if (isAuthRequired)
		{
		  const bool isPasswordBlank = ((CheckPassword(NULL) || CheckPassword(L"")));
		  isAuthRequired = !isPasswordBlank;
		}
	}
#endif

	return isAuthRequired;
}


/*++

	GetOwnerFromRegistry:

Gets owner settings from the registry.


Notes:

No errors if data not found in registry, it just clear the buffers passed
in.


--*/
static
void
GetOwnerFromRegistry(
	OWNER_PROFILE *pOwnerProfile,
	OWNER_NOTES   *pOwnerNotes
	)
{
	HKEY	hKey = NULL;
	DWORD	dwSize;
	DWORD	dwType;
	long	hRes;
	bool	bGotProfile = false;
	bool	bGotNotes = false;

	// szRegistryKey, szOwner, and szNotes are constants from owner.h
	hRes = RegOpenKeyExW(HKEY_CURRENT_USER, szRegistryKey,0, KEY_ALL_ACCESS, &hKey);
	if ( hRes != ERROR_SUCCESS )
		{
		goto done;
		}

	dwSize = sizeof(OWNER_PROFILE);
	hRes = RegQueryValueExW(hKey, (PTSTR)szOwner, 0, &dwType, (BYTE*)pOwnerProfile, &dwSize);
	if ( ( hRes == ERROR_SUCCESS ) &&
		 ( dwSize == sizeof(OWNER_PROFILE) ) )
		{
		bGotProfile = true;
		}

	dwSize = sizeof(OWNER_NOTES);
	hRes = RegQueryValueExW(hKey, (PTSTR)szNotes, 0, &dwType, (BYTE*)pOwnerNotes, &dwSize);
	if ( ( hRes == ERROR_SUCCESS ) &&
		 ( dwSize == sizeof(OWNER_NOTES) ) )
		{
		bGotNotes = true;
		}

done:
	if ( !bGotProfile )
		{
		memset(pOwnerProfile, 0, sizeof(OWNER_PROFILE));
		}

	if ( !bGotNotes )
		{
		memset(pOwnerNotes, 0, sizeof(OWNER_NOTES));
		}

	if ( hKey )
		{
		RegCloseKey(hKey);
		}
	return;
}




/*++

	SetAndShow:

Helper function to set text and show control.

Returns 0 if pszTest was NULL;
		1 otherwise.


The dialog/window routines to get and set text expect to receive mapped 
pointers.  Since the startui component is built into gwe, it must map the 
pointers explicitly.  

--*/
static
int
SetAndShow(
	HWND	hDlg,
	int		CtrlId,
	PTSTR	pszText
	)
{
	if ( *pszText )
		{
		SetDlgItemText(hDlg, CtrlId, pszText);
		ShowWindow(GetDlgItem(hDlg, CtrlId), SW_SHOW);
		return 1;
		}

	return 0;
}


static
void
AddString(
	PTSTR	pszText,
	PTSTR	pszNewStr
	)
{
	if ( *pszNewStr )
		{
		_tcscat(pszText, pszNewStr);
		_tcscat(pszText, TEXT(" "));
		}
	return;
}



static
LRESULT
CALLBACK
EditCtlProc(
	HWND	hwnd,
	UINT	message,
	WPARAM	wParam,
	LPARAM	lParam
	)
{

	switch ( message )
		{
		case WM_KEYDOWN:            
		case WM_CHAR:           
		case WM_LBUTTONDOWN:            
		case WM_LBUTTONUP:
			PostMessage(GetParent(hwnd),  message, wParam, lParam );
			return TRUE;


		//	Cannot have focus, return focus to window that lost it.
		case WM_SETFOCUS:
			if ( wParam )
				{
				SetFocus((HWND)wParam);
				}
			return TRUE;

		}

	return CallWindowProc(oldEditCtlProc, hwnd, message, wParam, lParam);
}




static
void
LoadStringFromResource(
	PTSTR   *ppsz,
	UINT    irsrc
	)
{
	int cch;

	*ppsz = (PTSTR)LocalAlloc (LMEM_FIXED, 255 * sizeof(TCHAR));
	if(!(*ppsz))
		{
		goto leave;
		}
	cch = LoadString(g_hinst, irsrc, *ppsz, 255);
	LocalReAlloc (*ppsz, (cch + 1) * sizeof(TCHAR), 0);
leave:
	return;

}

static
void
LoadGlobalStrings(
	void
	)
{
	LoadStringFromResource(&g_szStartupHome,				IDS_STARTUP_HOME);
	LoadStringFromResource(&g_szStartupWork,				IDS_STARTUP_WORK);
	LoadStringFromResource(&g_szStartupTimeFontName,		IDS_STARTUP_TIMEFONTNAME);
	LoadStringFromResource(&g_szStartupPasswordError,		IDS_STARTUP_PASSWORDERROR);
	LoadStringFromResource(&g_szStartupPasswordErrorTitle,	IDS_STARTUP_PASSWORDERRORTITLE);
	return;
}


static
void
FreeGlobalStrings(
	void
	)
{
	if ( g_szStartupHome )
		{
		LocalFree(g_szStartupHome);
		g_szStartupHome = NULL;
		}

	if ( g_szStartupWork )
		{
		LocalFree(g_szStartupWork);
		g_szStartupWork = NULL;
		}

	if ( g_szStartupTimeFontName )
		{
		LocalFree(g_szStartupTimeFontName);
		g_szStartupTimeFontName = NULL;
		}

	if ( g_szStartupPasswordError )
		{
		LocalFree(g_szStartupPasswordError);
		g_szStartupPasswordError = NULL;
		}

	if ( g_szStartupPasswordErrorTitle )
		{
		LocalFree(g_szStartupPasswordErrorTitle);
		g_szStartupPasswordErrorTitle = NULL;
		}

	return;
}

static 
bool 
CanDestroyDialog(
#ifndef USE_LASS_AUTH
	HWND hwndPass,
#else
	HWND hwndParent,
#endif 
	TCHAR* szText
	)
{

	//	If no password or we've already authenticated.
	if ( !isAuthRequired() || v_isAuthOccured )
	{
	  return true;
	}
    bool isAuthValid=false;
#ifndef USE_LASS_AUTH
	//	Get text from password window.
	SendMessage(hwndPass, WM_GETTEXT, PASSWORD_LENGTH + 1, (LPARAM)szText);
	_wcslwr(szText);
	isAuthValid = (CheckPassword(szText) != FALSE);
	//	If password matches, we're done.
	if ( isAuthValid )
	{
	  // autenticate the "default" user, but don't create
      // the password is used to unlock the user's sensitive data
        SetCurrentUser(L"default", (PBYTE)szText, _tcslen(szText)*sizeof(TCHAR), FALSE );
    }
#else
	isAuthValid = (TRUE ==  VerifyUser(&AE_STARTUI,L"StartUI",hwndParent,VU_UNTIL_SUCCESS,0));
#endif 
	v_isAuthOccured= isAuthValid;
	return isAuthValid;
}

/*++

	Startup_DlgProc:

--*/

BOOL
APIENTRY
Startup_DlgProc(
	HWND	hDlg,
	UINT	message,
	UINT	wParam,
	LONG	lParam
	)
{
#define MAX_TEXT	384

static	HBITMAP	hbm;
#ifndef USE_LASS_AUTH
static	HWND	hwndPass;
#endif 
static	LOGFONT	lFont;
static	HFONT	hDlgFont;
static	HFONT	hDlgFont1;
static	HFONT	hDlgFont2;
static	int		idTimer;


		TCHAR	szText[MAX_TEXT+1];
		TCHAR 	szText1[MAX_TEXT+1];
		int   i;


	switch (message)
		{
		case WM_INITDIALOG:
			//	Load and display the background bitmap.
			hbm = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_WINDOWSCE));
			SendMessage(
				GetDlgItem(hDlg, IDC_STATIC_PICT),
				STM_SETIMAGE,
				(WPARAM)IMAGE_BITMAP,
				(LPARAM) hbm);

			//	Misc other info for the dialog.
			LoadGlobalStrings();
#ifndef USE_LASS_AUTH
			hwndPass = GetDlgItem(hDlg, IDC_PASS);
#endif

			//	Set the font size of the various parts of the dialog.
			memset(&lFont, 0, sizeof(LOGFONT));
			hDlgFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
			if ( !hDlgFont )
				{
				hDlgFont = (HFONT)GetStockObject(SYSTEM_FONT);
				}
			GetObject(hDlgFont, sizeof(LOGFONT), &lFont);

			if (hDlgFont && lFont.lfHeight)
				{
				lFont.lfWeight =  FW_BOLD;

				lFont.lfHeight = 13;
				hDlgFont = CreateFontIndirect(&lFont);
				if ( hDlgFont )
					{
					SendMessage(GetDlgItem(hDlg, IDC_STATIC_PASS),   WM_SETFONT, (WPARAM)hDlgFont, 0L);
					SendMessage(GetDlgItem(hDlg, IDC_COMPANY), WM_SETFONT, (WPARAM)hDlgFont, 0L);
					SendMessage(GetDlgItem(hDlg, IDC_ADDRESS), WM_SETFONT, (WPARAM)hDlgFont, 0L);
					SendMessage(GetDlgItem(hDlg, IDC_WORK_PHONE), WM_SETFONT, (WPARAM)hDlgFont, 0L);
					SendMessage(GetDlgItem(hDlg, IDC_HOME_PHONE), WM_SETFONT, (WPARAM)hDlgFont, 0L);               
					}

				lFont.lfHeight = -16;
				hDlgFont1 = CreateFontIndirect(&lFont);
				if ( hDlgFont1 )
					{
					SendMessage(GetDlgItem(hDlg, IDC_STATIC_DAY), WM_SETFONT, (WPARAM)hDlgFont1, 0L);
					SendDlgItemMessage(hDlg, IDC_NAME , WM_SETFONT, (WPARAM)hDlgFont1, 0L);
					}

				_tcscpy(lFont.lfFaceName, g_szStartupTimeFontName);
				lFont.lfHeight = -20;
				hDlgFont2 = CreateFontIndirect(&lFont);
				if ( hDlgFont2 )
					{
					SendMessage(GetDlgItem(hDlg, IDC_STATIC_TIME),  WM_SETFONT, (WPARAM)hDlgFont2, 0L);
					}
				}
			

			
			// Set focus to the dialog itself, so WM_CHAR's are received.
			// If we're not using LASS and we requireAuth we'll switch the 
			// focus to the password field.
            SetFocus(hDlg);				
			if(	isAuthRequired() )
				{
				EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);	// disable close button
#ifndef USE_LASS_AUTH
				ShowWindow(hwndPass, SW_SHOW);
				ShowWindow(GetDlgItem(hDlg, IDC_STATIC_PASS), SW_SHOW);

				SendMessage(hwndPass, EM_LIMITTEXT, PASSWORD_LENGTH, 0L);
				SetFocus(hwndPass); 
#endif 
                }

			i = 0;
			if ( g_pOwnerNotes->NotesPowerUp )
				{
				i += SetAndShow(hDlg, IDC_NOTES, g_pOwnerNotes->Notes);
				}

			if ( !i)
				{
				ShowWindow(GetDlgItem(hDlg, IDC_NOTES),SW_HIDE);
				}


			i = 0;
			if ( g_pOwnerProfile->IDPowerUp )
				{
				i += SetAndShow(hDlg,	IDC_NAME,		g_pOwnerProfile->szName);
				i += SetAndShow(hDlg,	IDC_COMPANY,	g_pOwnerProfile->szCompany);
				i += SetAndShow(hDlg,	IDC_ADDRESS,	g_pOwnerProfile->szAdd);

				_tcscpy(szText, g_szStartupWork);
				AddString(szText,	g_pOwnerProfile->szWCC);
				AddString(szText,	g_pOwnerProfile->szWAC);
				AddString(szText,	g_pOwnerProfile->szWPhone);

				if ( _tcscmp(szText, g_szStartupWork) )
					{
					i += SetAndShow(hDlg, IDC_WORK_PHONE,szText);
					}

				_tcscpy(szText, g_szStartupHome);
				AddString(szText,	g_pOwnerProfile->szHCC);
				AddString(szText,	g_pOwnerProfile->szHAC);
				AddString(szText,	g_pOwnerProfile->szHPhone);

				if ( _tcscmp(szText, g_szStartupHome) )
					{
					i += SetAndShow(hDlg, IDC_HOME_PHONE, szText);
					}
				}

			//	Show picture if there is no user data.
			if ( !i )
				{
				ShowWindow(GetDlgItem(hDlg, IDC_STATIC_PICT), SW_SHOW);
				}


			oldEditCtlProc = (WNDPROC) GetWindowLong(GetDlgItem(hDlg,IDC_NOTES), GWL_WNDPROC);
			SetWindowLong(GetDlgItem(hDlg,IDC_NOTES),	GWL_WNDPROC,	(LONG)EditCtlProc);
			SetWindowLong(GetDlgItem(hDlg,IDC_ADDRESS),	GWL_WNDPROC,	(LONG)EditCtlProc);
			HideCaret(GetDlgItem(hDlg,IDC_NOTES));

			idTimer = SetTimer(hDlg, 1, 1000, NULL);
			return FALSE;


		case WM_TIMER:
			if ( GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, szText, MAX_TEXT) )
				{
				SetDlgItemText(hDlg, IDC_STATIC_TIME, szText);
				}

			SetWindowPos(GetDlgItem(hDlg,IDC_STATIC_TIME), HWND_TOP, 0,0, 0,0,
						 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

			if ( GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL, szText, MAX_TEXT))
				{
				GetDlgItemText(hDlg, IDC_STATIC_DAY, szText1, MAX_TEXT+1);

				//	To prevent flashing, only redraw if text has changed.
				if ( _tcscmp(szText, szText1) )
					{
					SetDlgItemText(hDlg, IDC_STATIC_DAY, szText);
					}
				}

			SetWindowPos(GetDlgItem(hDlg,IDC_STATIC_DAY), HWND_TOP, 0,0, 0,0,
						 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

			return TRUE;

		case WM_PAINT:
			{
			HDC hdc;
			PAINTSTRUCT ps;
			RECT rc;

			hdc = BeginPaint(hDlg, &ps);
			GetWindowRect(GetDlgItem(hDlg,IDC_STATIC_LINE), &rc);   
			ScreenToClient(hDlg, (PPOINT)&rc);

			rc.bottom = rc.top + 2;
			FillRect(hdc, &rc,  (HBRUSH)GetStockObject(BLACK_BRUSH));
			EndPaint(hDlg, &ps);
			}
			return TRUE;

		case WM_KEYDOWN:
		case WM_CHAR:
		case WM_LBUTTONDOWN:
			//This is guard when IME is KANA mode.
			if(WM_KEYDOWN == message && VK_KANA == wParam)
				break;
			//	If no auth, any key or mouse event finishes the dialog.
			if ( !isAuthRequired() )
				{
				goto dialog_done;
				}
			MessageBeep(0);
			break;

		case WM_COMMAND:
			switch ( LOWORD(wParam) )
				{
				case IDOK:
#ifndef USE_LASS_AUTH
					if(CanDestroyDialog(hwndPass, szText))
#else
					if(CanDestroyDialog(hDlg, NULL))
#endif
						{
						goto dialog_done;
						}
					else
						{
#ifndef USE_LASS_AUTH
						//	Complain if password does not match.
						MessageBox(
							hDlg,
							g_szStartupPasswordError,
							g_szStartupPasswordErrorTitle,
							MB_ICONEXCLAMATION | MB_OK );
						SetFocus(hwndPass);
						SendMessage(hwndPass, EM_SETSEL, 0L, -1);
#endif 
						return TRUE;
						}
	
				case IDCANCEL:  
					//	If no auth, we're done.
					if ( !isAuthRequired() )
						{
						goto dialog_done;
						}
					return FALSE;
				}
			break;

		case WM_DESTROY:
		case WM_CLOSE:
			// Check that it is OK to destroy the password dialog
			// Otherwise an application could bypass the dialog 
			// by sending a WM_CLOSE or WM_DESTROY 
#ifndef USE_LASS_AUTH
			if(CanDestroyDialog(hwndPass, szText))
#else
			if(CanDestroyDialog(hDlg, NULL))
#endif 
				{
				if(message == WM_DESTROY)
					{
					FreeGlobalStrings();
					}
				break;
				}
			else
				{
				// returning TRUE indicates that we've handled the message
				return TRUE;         
				}
		}

    return (FALSE);



dialog_done:
	if (idTimer)
		{
		KillTimer(hDlg, idTimer);
		idTimer = 0;
		}

	if (hbm)
		{
		DeleteObject(hbm);
		hbm = 0;
		}

	if (hDlgFont)
		{
		DeleteObject(hDlgFont);
		hDlgFont = 0;
		}

	if (hDlgFont1)
		{
		DeleteObject(hDlgFont1);
		hDlgFont1 = 0;
		}

	if (hDlgFont2)
		{
		DeleteObject(hDlgFont2);
		hDlgFont2 = 0;
		}

	Startup_DestroyDialogCallback();

	return TRUE;
}



void GetRegSettings()
{
   DWORD dwSize;
   DWORD dwType;
   DWORD dwValue;
   LONG  lResult;
   HKEY  hkey;

   fSystemStartupPasswordEnabled = false;

   lResult =
      RegOpenKeyEx(
          HKEY_LOCAL_MACHINE,
          szRegKeyAESystemStartup,
          NULL,
          KEY_READ,
          &hkey
          );

   if (lResult == ERROR_SUCCESS) 
   {
	   dwSize  = sizeof(dwValue);
	   RegQueryValueEx(hkey, szRegValueAEFrequency, NULL, &dwType, (PBYTE)&dwValue, &dwSize); 
	
	   RegCloseKey(hkey);

	   if ( dwValue != 0xFFFFFFFF )
	   {
		   fSystemStartupPasswordEnabled = true;		
	   }
   }

   return;
}
/*++

	Startup_WantStartupScreen:

--*/
BOOL
Startup_WantStartupScreen(
	void
	)
{
	// reset the auth occured flag every time we logon.
	v_isAuthOccured=false;
	iNumberOfRuns++;

	//	The owner profile and owner notes buffers are just allocated and left around.
	if ( !g_pOwnerProfile )
		{
		g_pOwnerProfile = (OWNER_PROFILE*)LocalAlloc(LMEM_FIXED, sizeof(OWNER_PROFILE));
		if ( !g_pOwnerProfile )
			{
			ERRORMSG(1, (TEXT("Could not allocate owner profile buffer.\r\n")));
			return FALSE;
			}
		}

	if ( !g_pOwnerNotes )
		{
		g_pOwnerNotes = (OWNER_NOTES*)LocalAlloc(LMEM_FIXED, sizeof(OWNER_NOTES));
		if ( !g_pOwnerNotes )
			{
			ERRORMSG(1, (TEXT("Could not allocate owner notes buffer.\r\n")));
			return FALSE;
			}
		}

	GetOwnerFromRegistry(g_pOwnerProfile, g_pOwnerNotes);
	GetRegSettings();

	//	If there is a password or the user has configured owner id or notes
	//	to display at startup or screen saver password protection is on, 
	//  then we want the startup screen.
	return  isAuthRequired()          	||
			g_pOwnerProfile -> IDPowerUp    ||
			g_pOwnerNotes -> NotesPowerUp;
}



/*++

	Startup_PowerOnNotification:

--*/
void
Startup_PowerOnNotification(
	HWND hwndDlg
	)
{
	//	Fake a timer message to force the date and time to appear.
	PostMessage(hwndDlg, WM_TIMER, 1, 0);
	return;
}





/*++

	Startup_PowerOffWhileStartupActiveNotification:

--*/
void
Startup_PowerOffWhileStartupActiveNotification (
	HWND hwndDlg
	)
{
	//	Hide the time and date so that the user does not see a stale
	//	date/time when the window reappears.
	SetWindowPos(
		GetDlgItem(hwndDlg, IDC_STATIC_TIME),
		HWND_TOP, 0,0, 0,0,
		SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

	SetWindowPos(
		GetDlgItem(hwndDlg,IDC_STATIC_DAY),
		HWND_TOP, 0,0, 0,0,
		SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

	return;
}





/*++

	Startup_Initialize:

--*/
void
Startup_Initialize(
	HINSTANCE hinst
	)
{
	g_hinst = hinst;
	return;
}

